package com.baidu.ueditor.upload;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.io.FileUtils;
import org.viva.alibaba.aliyun.oss.BucketService;
import org.viva.alibaba.aliyun.oss.OSSClientFactory;
import org.viva.alibaba.aliyun.oss.OSSClientProperties;
import org.viva.alibaba.aliyun.oss.ObjectService;
import org.viva.core.Log;
import org.viva.service.sys.WebsiteCache;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.Bucket;
import com.baidu.ueditor.define.AppInfo;
import com.baidu.ueditor.define.BaseState;
import com.baidu.ueditor.define.State;

public class StorageManager {
    public static final int BUFFER_SIZE = 8192;

    public StorageManager() {
    }

    public static State saveBinaryFile(byte[] data, String path) {
        File file = new File(path);

        State state = valid(file);

        if (!state.isSuccess()) {
            return state;
        }

        try {
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
            bos.write(data);
            bos.flush();
            bos.close();
        } catch (IOException ioe) {
            return new BaseState(false, AppInfo.IO_ERROR);
        }

        state = new BaseState(true, file.getAbsolutePath());
        state.putInfo("size", data.length);
        state.putInfo("title", file.getName());
        return state;
    }

    public static State saveFileByInputStream(InputStream is, String root, String path, long maxSize) {
        State state = null;

        File tmpFile = getTmpFile();

        byte[] dataBuf = new byte[2048];
        BufferedInputStream bis = new BufferedInputStream(is, StorageManager.BUFFER_SIZE);

        try {
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tmpFile), StorageManager.BUFFER_SIZE);

            int count = 0;
            while ((count = bis.read(dataBuf)) != -1) {
                bos.write(dataBuf, 0, count);
            }
            bos.flush();
            bos.close();

            if (tmpFile.length() > maxSize) {
                tmpFile.delete();
                return new BaseState(false, AppInfo.MAX_SIZE);
            }

            state = saveTmp2oss(tmpFile, root, path);

            if (!state.isSuccess()) {
                tmpFile.delete();
            }

            return state;

        } catch (IOException e) {
            e.printStackTrace();
        }
        return new BaseState(false, AppInfo.IO_ERROR);
    }

    public static State saveFileByInputStream(InputStream is, String root, String path) {
        State state = null;

        File tmpFile = getTmpFile();

        byte[] dataBuf = new byte[2048];
        BufferedInputStream bis = new BufferedInputStream(is, StorageManager.BUFFER_SIZE);

        try {
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tmpFile), StorageManager.BUFFER_SIZE);

            int count = 0;
            while ((count = bis.read(dataBuf)) != -1) {
                bos.write(dataBuf, 0, count);
            }
            bos.flush();
            bos.close();

            state = saveTmp2oss(tmpFile, root, path);

            if (!state.isSuccess()) {
                tmpFile.delete();
            }

            return state;
        } catch (IOException e) {
            Log.error(e, e);
        }
        return new BaseState(false, AppInfo.IO_ERROR);
    }

    private static File getTmpFile() {
        File tmpDir = FileUtils.getTempDirectory();
        String tmpFileName = (Math.random() * 10000 + "").replace(".", "");
        return new File(tmpDir, tmpFileName);
    }

    private static State saveTmpFile(File tmpFile, String root, String path) {
        State state = null;
        File targetFile = new File(root + path);

        if (targetFile.canWrite()) {
            return new BaseState(false, AppInfo.PERMISSION_DENIED);
        }
        try {
            FileUtils.moveFile(tmpFile, targetFile);
        } catch (IOException e) {
            return new BaseState(false, AppInfo.IO_ERROR);
        }

        state = new BaseState(true);
        Log.debug("down success : " + root + path);
        // state.putInfo("url", "http://localhost:8080/war/oss" + path);
        state.putInfo("url", WebsiteCache.get("sys.host") + "/oss/down?path=" + path);
        state.putInfo("size", targetFile.length());
        state.putInfo("title", targetFile.getName());
        return state;
    }

    private static State saveTmp2oss(File tmpFile, String root, String path) {
        if (OSSClientProperties.useStatus) {
            String tp = root + path;

            State state = new BaseState(true);
            try {
                OSSClient client = OSSClientFactory.createOSSClient();

                Bucket bucket = BucketService.create(client, OSSClientProperties.bucketName);
                // 获取key，即文件的上传路径
                // String key = stateJson.getString("url").replaceFirst("/",
                // "");
                try {
                    FileInputStream fileInputStream = new FileInputStream(tmpFile);
                    // PutObjectResult result =

                    ObjectService.putObject(client, bucket.getName(), tp.replaceFirst("/", ""), fileInputStream);
                    Log.debug("upload image[" + tp + "] to aliyun OSS success.");
                } catch (FileNotFoundException e) {
                    Log.error("upload to aliyun OSS error, FileNotFoundException。");
                } catch (NumberFormatException e) {
                    Log.error("upload to aliyun OSS error, NumberFormatException。");
                } catch (IOException e) {
                    Log.error("upload to aliyun OSS error, IOException。");
                } catch (Exception e) {
                    Log.error("upload to aliyun OSS error, IOException。");
                }

                state.putInfo("url", OSSClientProperties.endPoint + tp);
                state.putInfo("size", tmpFile.length());
                state.putInfo("title", tmpFile.getName());
                tmpFile.delete();
            } catch (Exception e) {
                Log.error(e, e);
                return new BaseState(false, AppInfo.IO_ERROR);
            }

            return state;
        } else {
            return saveTmpFile(tmpFile, root, path);
        }
    }

    private static State valid(File file) {
        File parentPath = file.getParentFile();
        if ((!parentPath.exists()) && (!parentPath.mkdirs())) {
            return new BaseState(false, AppInfo.FAILED_CREATE_FILE);
        }
        if (!parentPath.canWrite()) {
            return new BaseState(false, AppInfo.PERMISSION_DENIED);
        }
        return new BaseState(true);
    }
}
